#pragma once
#include "Mutex.hpp"
#include "cond.hpp"
#include "log.hpp"
#include "pthread.hpp"
#include <vector>
#include <queue>
namespace PthreadPoolModule
{

    using namespace MutexMoudle;
    using namespace CondModule;
    using namespace LogModule;
    using namespace PthreadModlue;

    template <typename T>
    class PthreadPool
    {
    private:
        void WakeUpAllThread()
        {
            LockGuard lockguard(_mutex);
            if (_sleepnum)
                _cond.Broadcast();
            LOG(LogLevel::INFO) << "唤醒所有的休眠线程";
        }
        void WakeUpOne()
        {
            _cond.Signal();
            LOG(LogLevel::INFO) << "唤醒一个休眠线程";
        }
        PthreadPool(int num = 5)
            : _num(num),
              _isrunning(false),
              _sleepnum(0)
        {
            for (int i = 0; i < _num; i++)
            {
                _threads.emplace_back([this]()
                                      { HandlerTask(); });
            }
        }

    public:
        // 创建单例
        static PthreadPool<T> *GetInstance()
        {
            // 加锁防止多消费者
            if (_ins == nullptr)
            {
                LockGuard lock(_insmutex);
                LOG(LogLevel::DEBUG) << "获取单例....";
                if (_ins == nullptr)
                {
                    LOG(LogLevel::DEBUG) << "首次使用单例, 创建之....";
                    _ins = new PthreadPool<T>();
                    _ins->Start();
                }
            }

            return _ins;
        }
        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true;
            LOG(LogLevel::INFO) << "线程池开始启动···";
            for (auto &ch : _threads)
            {
                ch.Start();
                LOG(LogLevel::INFO) << "新线程" << ch.Name() + "启动了";
            }
        }
        void Stop()
        {
            if (!_isrunning)
                return;
            _isrunning = false;
            // 进程停止
            // 可能有的在休眠
            // 有的在处理任务
            // 我们要把休眠的全部唤醒
            // 并且把任务队列的任务全部执行完
            // 才可以退出线程池
            //  唤醒所有的线层
            WakeUpAllThread();
        }
        void Join()
        {
            for (auto &ch : _threads)
            {
                ch.Join();
            }
        }
        bool Enqueue(const T &in)
        {
            if (_isrunning)
            {
                LockGuard lock(_mutex);
                {
                    _taskq.push(in);
                    if (_threads.size() == _sleepnum)
                        WakeUpOne();
                    return true;
                }
            }
            return false;
        }
        // 该函数结束就会进行线程就运行完毕了
        void HandlerTask()
        {

            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            LOG(LogLevel::INFO) << name << " 处理任务...";
            // 消费者
            // 多个线程就是消费者
            while (true)
            {
                T task;
                LockGuard lock(_mutex);
                {
                    while (_taskq.empty() && _isrunning)
                    {
                        // 去进行等待
                        _sleepnum++;
                        _cond.Wait(_mutex);
                        _sleepnum--;
                    }
                    if (!_isrunning && _taskq.empty())
                    {

                        LOG(LogLevel::DEBUG) << "线程池退出";
                        break;
                    }
                    LOG(LogLevel::INFO) << name << " 退出了, 线程池退出&&任务队列为空";
                    task = _taskq.front();
                    _taskq.pop();
                }
                // 在临界区外面执行任务可有多个线程共同执行
                 task();
            }
        }

    private:
        std::vector<Pthread> _threads;
        int _num;
        Mutex _mutex;
        Cond _cond;
        std::queue<T> _taskq;
        bool _isrunning; // 用来标记线程退出
        int _sleepnum;   // 睡眠的线程数

        static PthreadPool<T> *_ins; // 单例指针
        // 我们用的单例在开始时没有我们的锁因此我们这把锁要定义为静态的
        static Mutex _insmutex;
    };
    // 静态成员的初始化
    template <typename T>
    PthreadPool<T> *PthreadPool<T>::_ins = nullptr;

    template <typename T>
    Mutex PthreadPool<T>::_insmutex;
}